package com.sky.websocket;

import com.sky.config.EmpProperties;
import com.sky.service.ApplicationContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket服务端处理类
 * WebsocketServer类在jvm中有2个实例对象，
 * 一个是spring ioc容器生成并管理的，
 * 一个是tomcat服务器生成并管理的。
 * ioc管理的bean是可以做注入的，tomcat管理的实例仅仅是new了一个对象，不会做属性的注入。
 * */
@Slf4j
@Component
@ServerEndpoint("/ws/{sid}")
public class WebsocketServer {

    /**
     * 保存客户端id和session对应关系
     * */
    private Map<String, Session> sessionMap = new ConcurrentHashMap<>();


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 当与客户端建立连接以后，springboot框架回调此方法
     * @param  session 用来与客户端进行通信的
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid")String sid){
        // 从容器中获取Bean对象
        WebsocketServer bean = ApplicationContextUtil.getBean(WebsocketServer.class);
        StringRedisTemplate redisTemplate = ApplicationContextUtil.getBean(StringRedisTemplate.class);
        EmpProperties empProperties = ApplicationContextUtil.getBean(EmpProperties.class);
        // 保存sid到redis，key：商户id，value：sid
        redisTemplate.opsForValue().set("emp:"+empProperties.getEmpId(), ""+sid);
        log.info("与客户端建立连接， sid:{}", sid);
        bean.sessionMap.put(sid, session);
        log.info("sessionMap.size():{}, sessionMap hashcode:{}, this.hashCode:{}", sessionMap.size(), sessionMap.hashCode(), this.hashCode());
    }

    /**
     * 当收到来自客户端的消息以后，springboot框架回调此方法
     */
    @OnMessage
    public void onMessage(String msg,  @PathParam("sid")String sid){
        log.info("收到来自客户端的消息， msg：{}， sid:{}", msg, sid);
    }

    /**
     * 当与客户端断开以后，springboot框架回调此方法
     */
    @OnClose
    public void onclose(@PathParam("sid")String sid){
        log.info("与客户端断开连接，sid:{}",  sid);
        WebsocketServer bean = ApplicationContextUtil.getBean(WebsocketServer.class);
        StringRedisTemplate redisTemplate = ApplicationContextUtil.getBean(StringRedisTemplate.class);
        EmpProperties empProperties = ApplicationContextUtil.getBean(EmpProperties.class);
        // 删除redis
        Long empId = empProperties.getEmpId();
        redisTemplate.delete("emp:"+empId);
        // 防止内存泄露
        bean.sessionMap.remove(sid);
    }

    /**
     * 单发
     * */
    public void sendToClient(String sid, String message)throws Exception{
        // 根据客户端的sid查找与客户端对应的session对象，就代表了一个tcp的连接
        Session session = sessionMap.get(sid);
        if(session == null){
            log.error("客户端不在线，无法发送消息");
        }else {
            // 向客户端发消息
            session.getBasicRemote().sendText(message);
        }
    }

    /**
     * 群发
     * */
    public void send2All(String message)throws Exception{
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            session.getBasicRemote().sendText(message);
        }
    }

}
